
#include <cassert>

#include "Scene\light.h"

/*Light::Light()
	: m_position(0.0f, 0.0f, 0.0f, 1.0f),
	  m_direction(0.0f, 0.0f, 0.0f, 0.0f),
	  m_angle(D3DX_PIF),
	  m_radius(D3D10_FLOAT32_MAX),
	  m_ambient(1.0f, 0.9f, 0.2f, 1.0f),
	  m_diffuse(1.0f, 0.9f, 0.2f, 1.0f),
	  m_specular(1.0f, 0.9f, 0.2f, 1.0f),
	  m_constant_attenuation(0.0f),
	  m_linear_attenuation(0.0f),
	  m_quadratic_attenuation(0.0f),
	  m_exponent(1.0f)
{
}*/

Light::Light(CONST Vector4& position,
			 CONST Vector4& direction,
			 FLOAT angle,
			 FLOAT radius,
			 CONST RGBColor& ambient,
			 CONST RGBColor& diffuse,
			 CONST RGBColor& specular,
			 FLOAT constant_attenuation,
			 FLOAT linear_attenuation,
			 FLOAT quadratic_attenuation,
			 FLOAT exponent)
	: m_position(position),
	  m_direction(direction),
	  m_angle(angle),
	  m_radius(radius),
	  m_ambient(ambient),
	  m_diffuse(diffuse),
	  m_specular(specular),
	  m_constant_attenuation(constant_attenuation),
	  m_linear_attenuation(linear_attenuation),
	  m_quadratic_attenuation(quadratic_attenuation),
	  m_exponent(exponent)
{
	assert(m_position.IsPoint());
	assert(m_direction.IsVector());
	assert(0.0f <= angle && angle <= D3DX_PIF);
	assert(m_radius >= 0);
	assert(m_constant_attenuation >= 0);
	assert(m_linear_attenuation >= 0);
	assert(m_quadratic_attenuation >= 0);
	assert(m_constant_attenuation + m_linear_attenuation + m_quadratic_attenuation != 0);
	assert(m_exponent >= 0);
}


Light::Light(FLOAT px, FLOAT py, FLOAT pz, FLOAT pw,
			 FLOAT dx, FLOAT dy, FLOAT dz,
			 FLOAT angle,
			 FLOAT radius,
			 FLOAT ar, FLOAT ag, FLOAT ab,
			 FLOAT dr, FLOAT dg, FLOAT db,
			 FLOAT sr, FLOAT sg, FLOAT sb,
			 FLOAT constant_attenuation,
			 FLOAT linear_attenuation,
			 FLOAT quadratic_attenuation,
			 FLOAT exponent)
	: m_position(px, py, pz, pw),
	  m_direction(dx, dy, dz, 0.0f),
	  m_angle(angle),
	  m_radius(radius),
	  m_ambient(ar, ag, ab),
	  m_diffuse(dr, dg, db),
	  m_specular(sr, sg, sb),
	  m_constant_attenuation(constant_attenuation),
	  m_linear_attenuation(linear_attenuation),
	  m_quadratic_attenuation(quadratic_attenuation),
	  m_exponent(exponent)
{
	assert(0.0f <= angle && angle <= D3DX_PIF);
	assert(m_radius >= 0);
	assert(m_constant_attenuation >= 0);
	assert(m_linear_attenuation >= 0);
	assert(m_quadratic_attenuation >= 0);
	assert(m_constant_attenuation + m_linear_attenuation + m_quadratic_attenuation != 0);
	assert(m_exponent >= 0);
}


Light::~Light()
{
}


Light::Light(CONST Light& other)
	: m_position(other.m_position),
	  m_direction(other.m_direction),
	  m_angle(other.m_angle),
	  m_radius(other.m_radius),
	  m_ambient(other.m_ambient),
	  m_diffuse(other.m_diffuse),
	  m_specular(other.m_specular),
	  m_constant_attenuation(other.m_constant_attenuation),
	  m_linear_attenuation(other.m_linear_attenuation),
	  m_quadratic_attenuation(other.m_quadratic_attenuation),
	  m_exponent(other.m_exponent)
{
}


Light& Light::operator = (CONST Light& other)
{
	// Self-assignement.
	if(this == &other)
		return *this;

	// Copy.
	m_position = other.m_position;
	m_direction = other.m_direction;
	m_angle = other.m_angle;
	m_radius = other.m_radius;
	m_ambient = other.m_ambient;
	m_diffuse = other.m_diffuse;
	m_specular = other.m_specular;
	m_constant_attenuation = other.m_constant_attenuation;
	m_linear_attenuation = other.m_linear_attenuation;
	m_quadratic_attenuation = other.m_quadratic_attenuation;
	m_exponent = other.m_exponent;

	return *this;
}

Light::Type Light::GetType() CONST
{
	// Directional light have effect everywhere so w = 0.
	if(m_position.GetW() == 0)
		return DIRECTIONAL;

	// Point light have effect all around so angle = D3DX_PI.
	if(m_angle == D3DX_PIF)
		return POINT;

	// Otherwise it's a spot light.
	return SPOT;
}


Vector4 Light::GetPosition() CONST
{
	return m_position;
}


VOID Light::SetPosition(CONST Vector4& position)
{
	assert(position.IsPoint());

	m_position = position;
}


VOID Light::SetPosition(FLOAT x, FLOAT y, FLOAT z)
{
	m_position = Vector4::CreatePoint(x, y, z);
}


Vector4 Light::GetDirection() CONST
{
	return m_direction;
}


VOID Light::SetDirection(CONST Vector4& direction)
{
	assert(direction.IsVector());

	m_direction = direction;
}


VOID Light::SetDirection(FLOAT x, FLOAT y, FLOAT z)
{
	m_direction = Vector4::CreateVector(x, y, z);
}


FLOAT Light::GetAngle() CONST
{
	return m_angle;
}


VOID Light::SetAngle(FLOAT angle)
{
	assert(0.0f <= angle && angle <= D3DX_PIF);

	m_angle = angle;
}


FLOAT Light::GetRadius() CONST
{
	return m_radius;
}


VOID Light::SetRadius(FLOAT radius)
{
	m_radius = radius;
}


RGBColor Light::GetAmbient() CONST
{
	return m_ambient;
}


VOID Light::SetAmbient(CONST RGBColor& color)
{
	m_ambient = color;
}


VOID Light::SetAmbient(FLOAT r, FLOAT g, FLOAT b)
{
	m_ambient = RGBColor(r, g, b);
}


RGBColor Light::GetDiffuse() CONST
{
	return m_diffuse;
}


VOID Light::SetDiffuse(CONST RGBColor& color)
{
	m_diffuse = color;
}


VOID Light::SetDiffuse(FLOAT r, FLOAT g, FLOAT b)
{
	m_diffuse = RGBColor(r, g, b);
}


RGBColor Light::GetSpecular() CONST
{
	return m_specular;
}


VOID Light::SetSpecular(CONST RGBColor& color)
{
	m_specular = color;
}


VOID Light::SetSpecular(FLOAT r, FLOAT g, FLOAT b)
{
	m_specular = RGBColor(r, g, b);
}


FLOAT Light::GetConstantAttenuation() CONST
{
	return m_constant_attenuation;
}


VOID Light::SetConstantAttenuation(FLOAT x)
{
	assert(m_constant_attenuation >= 0);
	assert(m_constant_attenuation + m_linear_attenuation + m_quadratic_attenuation != 0);

	m_constant_attenuation = x;
}


FLOAT Light::GetLinearAttenuation() CONST
{
	return m_linear_attenuation;
}


VOID Light::SetLinearAttenuation(FLOAT x)
{
	assert(m_linear_attenuation >= 0);
	assert(m_constant_attenuation + m_linear_attenuation + m_quadratic_attenuation != 0);

	m_linear_attenuation = x;
}


FLOAT Light::GetQuadraticAttenuation() CONST
{
	return m_quadratic_attenuation;
}


VOID Light::SetQuadraticAttenuation(FLOAT x)
{
	assert(m_quadratic_attenuation >= 0);
	assert(m_constant_attenuation + m_linear_attenuation + m_quadratic_attenuation != 0);

	m_quadratic_attenuation = x;
}


FLOAT Light::GetExponent() CONST
{
	return m_exponent;
}


VOID Light::SetExponent(FLOAT exponent)
{
	assert(m_exponent >= 0);

	m_exponent = exponent;
}